/*
** i18n.c: the implements of i18n.h
**
** Copyright (C) 2007-2008 SKY-MOBI AS.  All rights reserved.
**
** Create date: 2007-12-27 by wandonglin
**
** This file is part of the simple gui library.
** It may not be redistributed under any circumstances.
*/

#include "i18n.h"

#include "mrc_base.h"
//#include "mrc_base_i.h"
#include "mrc_exb.h"
#define RES_FILENAME	"res_lang%d.rc"
#define MAGIC_CODE		0x0774660D

#define SGL_SPRINTF sprintf
#define SGL_TRACE mrc_printf
#define SGL_FREE free
#define SGL_MALLOC malloc
#ifndef MR_PLAT_VALUE_BASE
#define MR_PLAT_VALUE_BASE (1000)
#endif
//FILE HEADER
typedef struct RES_FILE_HEADER_T
{
    DWORD magic; //the magic code
    DWORD appid; //the application id
    DWORD version;//the resource version
    DWORD strings; // the string count
    DWORD reserve1; //reserve space
    DWORD reserve2; //reserve space

    BYTE supprts[8]; //one language has a bit information in this array
    DWORD count; //the language contains in this file
    //DWORD offset[]; //the offset for the language
} RES_FILE_HEADER;


//LANGUAGE SEGMENT HEADER
typedef struct RES_LANG_HEADER_T
{
    DWORD id;  // the language id from 0
    DWORD size; // the string data size
    DWORD checksum; // the string data checksum
    DWORD reserve; // reserve space
} RES_LANG_HEADER;


//language table
static struct LANGUAGE_T
{
    const Uint16* offset; //data offset table
    const Uint8* data; //data
} languages[SGL_MAX_LNG_COUNT];


//local datas
static DWORD cur_lang;

//////////////////////////////////////////////////////////////////////////


#if BIG_ENDIAN
static VOID
I18n_BigEndian2(Uint16* pArr, DWORD size)
{
    DWORD i;
    PBYTE pb;
    BYTE tmp;

    for(i = 0; i < size; i++)
    {
        pb = (PBYTE)&pArr[i];
        tmp = pb[0];
        pb[0] = pb[1];
        pb[1] = tmp;
    }
}


static VOID
I18n_BigEndian4(DWORD* pArr, DWORD size)
{
    DWORD i;
    PBYTE pb;
    BYTE tmp;

    for(i = 0; i < size; i++)
    {
        pb = (PBYTE)&pArr[i];
        tmp = pb[0];
        pb[0] = pb[3];
        pb[3] = tmp;
        tmp = pb[1];
        pb[1] = pb[2];
        pb[2] = tmp;
    }
}
#endif


VOID GUIAPI
SGL_I18nInitialize(VOID)
{
    // TODO:
}


BOOL GUIAPI
SGL_SetCurrentLanguage(DWORD lang)
{
    lang -= MR_PLAT_VALUE_BASE;

    if(lang == cur_lang || lang >= SGL_MAX_LNG_COUNT)
        return FALSE;

    cur_lang = lang;
    return TRUE;
}


DWORD GUIAPI
SGL_GetCurrentLanguage(VOID)
{
    return cur_lang + MR_PLAT_VALUE_BASE;
}

#ifdef RES_LOAD_FILENAME
static BOOL
SGL_CheckFileHeader(RES_FILE_HEADER* pHeader, DWORD lang)
{
    mrc_appInfoSt * pAppInfo = mrc_getAppInfo();

    if(pHeader->magic != MAGIC_CODE
       || pHeader->appid != (DWORD)pAppInfo->id
       || pHeader->strings != RES_STRING_COUNT
       || pHeader->count == 0
       || pHeader->count > SGL_MAX_LNG_COUNT
       || !(pHeader->supprts[lang / 8] & (1 << lang % 8)))
        return FALSE;

    return TRUE;
}


static DWORD
SGL_GenerateCheckSum(PBYTE pData, DWORD size)
{
    DWORD i = 0;
    DWORD checksum = 0;

    for(i = 0; i < size; i++)
        checksum += pData[i];

    return checksum;
}
#endif

static BOOL
SGL_LoadResourceFromMrp(DWORD lang)
{
    CHAR filename[24], RecBuf[32];
    uint8* pBuf = NULL;
    int32 len = 0, ret;
    SGL_SPRINTF(filename, RES_FILENAME, lang);
    mrc_memset(RecBuf, 0, sizeof(RecBuf));
    ret = mrc_GetMrpInfo(mrc_getPackName(), MRP_FILENAME, (uint8*)&RecBuf, 32);
    mrc_strcat(RecBuf, "\\mul_lan.mrp");

    if(ret <= 0)
    {
        if(MR_SUCCESS != mrc_readFileFromMrpEx(NULL, filename, (uint8**)&pBuf, &len, 0))
        {
            SGL_TRACE("Failed to read resource: %s\n", filename);
            return FALSE;
        }
    }
    else if(MR_SUCCESS != mrc_readFileFromMrpEx(RecBuf, filename, (uint8**)&pBuf, &len, 0))
    {
        if(MR_SUCCESS != mrc_readFileFromMrpEx(NULL, filename, (uint8**)&pBuf, &len, 0))
        {
            SGL_TRACE("Failed to read resource: %s\n", filename);
            return FALSE;
        }
    }

#if BIG_ENDIAN
    I18n_BigEndian2((Uint16*)pBuf, RES_STRING_COUNT);
#endif
    languages[lang].offset = (Uint16*)pBuf;
    languages[lang].data = pBuf + RES_STRING_COUNT * 2;
    return TRUE;
}


#ifdef RES_LOAD_FILENAME
static BOOL
SGL_LoadResourceFromFile(PCSTR filename, DWORD lang)
{
    int32 stream;
    BOOL r = FALSE;
    RES_FILE_HEADER filehdr;
    RES_LANG_HEADER langhdr;
    DWORD offset[SGL_MAX_LNG_COUNT];
    PBYTE pBuf = NULL;

    if(0 == (stream = mrc_open(filename, MR_FILE_RDONLY)))
    {
        SGL_TRACE("%s, %d: failed to open file : %s\n", __FILE__, __LINE__, filename);
        return FALSE;
    }

    if(sizeof(RES_FILE_HEADER) != mrc_read(stream, &filehdr, sizeof(RES_FILE_HEADER))
       || !SGL_CheckFileHeader(&filehdr, lang))
    {
        SGL_TRACE("%s, %d: failed to read file header\n", __FILE__, __LINE__);
        goto loadfile_error;
    }

#if BIG_ENDIAN
    I18n_BigEndian4((DWORD*)pBuf, 4);
    I18n_BigEndian4((DWORD*)&filehdr.count, 1);
#endif

    if(filehdr.version <= RES_VERSION)
    {
        SGL_TRACE("%s, %d: small resource version \n", __FILE__, __LINE__);
        goto loadfile_error;
    }

    if((int32)(filehdr.count * sizeof(DWORD)) != mrc_read(stream, offset, filehdr.count * sizeof(DWORD)))
    {
        SGL_TRACE("%s, %d: failed to load offset information \n", __FILE__, __LINE__);
        goto loadfile_error;
    }

#if BIG_ENDIAN
    I18n_BigEndian4((DWORD*)offset, filehdr.count);
#endif

    if(MR_SUCCESS != mrc_seek(stream, sizeof(RES_FILE_HEADER) + sizeof(DWORD)*filehdr.count + offset[lang], MR_SEEK_SET))
    {
        SGL_TRACE("%s, %d: failed to seek \n", __FILE__, __LINE__);
        goto loadfile_error;
    }

    if(sizeof(RES_LANG_HEADER) != mrc_read(stream, &langhdr, sizeof(RES_LANG_HEADER)))
    {
        SGL_TRACE("%s, %d: failed to read language header \n", __FILE__, __LINE__);
        goto loadfile_error;
    }

#if BIG_ENDIAN
    I18n_BigEndian4((DWORD*)pBuf, 4);
#endif
    pBuf = (PBYTE)SGL_MALLOC(sizeof(Uint16) * RES_STRING_COUNT + langhdr.size);

    if(pBuf == NULL)
    {
        SGL_TRACE("%s, %d: failed to malloc memory \n", __FILE__, __LINE__);
        goto loadfile_error;
    }

    if((int32)(sizeof(Uint16) * RES_STRING_COUNT + langhdr.size) != mrc_read(stream, pBuf, sizeof(Uint16) * RES_STRING_COUNT + langhdr.size))
    {
        SGL_TRACE("%s, %d: failed to read language data \n", __FILE__, __LINE__);
        SGL_FREE(pBuf);
        goto loadfile_error;
    }

    if(langhdr.checksum != SGL_GenerateCheckSum(pBuf + RES_STRING_COUNT * sizeof(Uint16), langhdr.size))
    {
        SGL_TRACE("%s, %d: buffer length error\n", __FILE__, __LINE__);
        SGL_FREE(pBuf);
        goto loadfile_error;
    }

#if BIG_ENDIAN
    I18n_BigEndian2((Uint16*)pBuf, RES_STRING_COUNT);
#endif
    languages[lang].offset = (Uint16*)pBuf;
    languages[lang].data = pBuf + sizeof(Uint16) * RES_STRING_COUNT;
    r = TRUE;
loadfile_error:

    if(stream) mrc_close(stream);

    return r;
}

#endif


BOOL GUIAPI
SGL_LoadResource(DWORD lang)
{
#ifdef RES_LOAD_FILENAME

    //try to load the resource from file
    if(SGL_LoadResourceFromFile(RES_LOAD_FILENAME, lang))
        return TRUE;

#endif
    //load from mrp
    return SGL_LoadResourceFromMrp(lang);
}


BOOL GUIAPI
SGL_ReleaseResource(DWORD lang)
{
    lang -= MR_PLAT_VALUE_BASE;

    if(languages[cur_lang].offset)
    {
        SGL_FREE((void*)languages[lang].offset);
        languages[lang].data = NULL;
        languages[lang].offset = NULL;
        return TRUE;
    }

    return FALSE;
}


PCWSTR GUIAPI SGL_LoadString(DWORD str)
{
    if(str >= RES_STRING_COUNT)
        return NULL;

    if(!languages[cur_lang].offset)
    {
        if(!SGL_LoadResource(cur_lang))
            return NULL;
    }

    return (PCWSTR)(languages[cur_lang].data + languages[cur_lang].offset[str]);
}

